import 'dart:math';

import 'package:easy_debounce/easy_debounce.dart';
import 'package:extended_tabs/extended_tabs.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/rendering.dart';
import 'package:lib_uikit/widgets/refresh_list/gt_refresh_custom_view.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';

//联动滚动视图-支持下拉刷新控件在整体页面顶部
class GTLinkedScrollview extends StatefulWidget {
  const GTLinkedScrollview({
    super.key,
    required this.onRefresh,
    required this.slivers,
    required this.pinnedWidget,
    required this.pinnedWidgetHeight,
    required this.horizontalContents,
    this.scrollCallBack,
    this.initRefresh,
    this.enablePullUp,
    this.onLoad,
    required this.tabController,
  });
  final bool? initRefresh;
  final ValueChanged<ScrollController>? scrollCallBack;
  final List<Widget> slivers;
  final Widget pinnedWidget;
  final double pinnedWidgetHeight;
  final List<Widget> horizontalContents;
  final void Function(RefreshController controller) onRefresh;
  final void Function(RefreshController controller)? onLoad;
  final TabController tabController;
  final bool? enablePullUp;

  @override
  State<GTLinkedScrollview> createState() => _GTLinkedScrollviewState();
}

class _GTLinkedScrollviewState extends State<GTLinkedScrollview> {
  final _cachedHorizontalContentHeights = <int, double>{}; // 缓存水平滚动内容的高度
  double _pinnedHeaderOffset = 0; // 吸顶组件在滚动区域内距离顶部的偏移量
  double _pinnedHeaderHeight = 0; // 吸顶组件的高度
  int _currentPage = 0; // 当前页面
  bool _isPointerUp = true; // 指针是否抬起

  final _pageViewHeight = ValueNotifier<double>(0);
  final _minPageHeight = ValueNotifier(0.0); // PageView的最小高度
  final Map<int, ValueNotifier<double>> _contentOffsets = {}; // 页面的偏移量
  // late final PageController _horizontalPageController; // = PageController();
  final _verticalScrollController = ScrollController();
  // final _refreshController = RefreshController();
  final _customScrollViewKey = GlobalKey();
  final _pinnedHeaderKey = GlobalKey();

  void setPinnedHeaderOffsetAndHeight(double offset, double height, double scrollViewHeight) {
    if (_pinnedHeaderOffset != offset || _pinnedHeaderHeight != height) {
      _pinnedHeaderOffset = offset;
      _pinnedHeaderHeight = height;

      final minPageHeight = scrollViewHeight - _pinnedHeaderHeight;
      if (minPageHeight != _minPageHeight.value) {
        _minPageHeight.value = minPageHeight;
        _resetPageViewHeight();
      }
    }
  }

  set currentPage(int value) {
    if (_currentPage != value) {
      _currentPage = value;

      Future.microtask(() {
        _resetPageViewHeight();
        _resetPageOffset();
      });
    }
  }

  @override
  void initState() {
    super.initState();
  
    widget.tabController.addListener(() {
      final page = widget.tabController.index;
      if (_isPointerUp && page == page.toInt()) {
        currentPage = page.toInt();
      }
    });

    _verticalScrollController.addListener(_listenVerticalScroll);

    _initial();
  }

  void _listenVerticalScroll() {
    widget.scrollCallBack?.call(_verticalScrollController);
    // final page = (_horizontalPageController.page ?? 0).round();
    final page = widget.tabController.index;
    currentPage = page;

    _resetPageViewHeight();

    EasyDebounce.debounce('earn_coin_scrollview_verticalScrollController', const Duration(milliseconds: 50), () {
      if (_isPointerUp) {
        _calcPinnedHeaderOffset();
        _setOtherPageOffset();
      } else {
        _listenVerticalScroll();
      }
    });
  }

  @override
  void didUpdateWidget(covariant GTLinkedScrollview oldWidget) {
    super.didUpdateWidget(oldWidget);
    _initial();
  }

  @override
  void dispose() {
   
    _verticalScrollController.dispose();
    super.dispose();
  }

  void _initial() {
    _contentOffsets.clear();
    for (var i = 0; i < widget.horizontalContents.length; i++) {
      _contentOffsets[i] = ValueNotifier<double>(0);
    }
  }

  // 计算吸顶组件在滚动区域内距离顶部的距离
  void _calcPinnedHeaderOffset() {
    final scrollViewRenderObject = _customScrollViewKey.currentContext?.findRenderObject();
    final pinnedHeaderRenderObject = _pinnedHeaderKey.currentContext?.findRenderObject();
    if (scrollViewRenderObject != null && pinnedHeaderRenderObject != null) {
      final scrollViewOffset = (scrollViewRenderObject as RenderBox).localToGlobal(Offset.zero);
      final pinnedHeaderOffset = (pinnedHeaderRenderObject as RenderBox).localToGlobal(Offset.zero);
      var offset = pinnedHeaderOffset.dy - scrollViewOffset.dy;
      if (offset > 0) {
        offset += _verticalScrollController.offset;
      } else {
        _resetPageViewHeight();
        return;
      }
      setPinnedHeaderOffsetAndHeight(
        offset,
        pinnedHeaderRenderObject.paintBounds.size.height,
        scrollViewRenderObject.size.height,
      );
    }
  }

  // // 计算目标页面的最大可滚动范围
  // double _calcMaxScrollExtent(int index) {
  //   final pageHeight = _cachedHeights[index] ?? 0;
  //   final contentHeight = _pinnedHeaderOffset + _pinnedHeaderHeight + pageHeight;
  //   final maxScrollExtent = contentHeight - _scrollViewHeight;
  //   return maxScrollExtent;
  // }

  void _setPageHeight(int index, double height) {
    _cachedHorizontalContentHeights[index] = height;
    // final page = _horizontalPageController.page ?? 0;
    final page = widget.tabController.index;
    if (index == page) {
      _pageViewHeight.value = height;
    }

    if (index == _currentPage) {
      /// 当前页面的内容高度发生变化时，重新计算其它页面内容的偏移量
      SchedulerBinding.instance.addPostFrameCallback((timeStamp) {
        _setOtherPageOffset();
      });
    }

    // 重新计算这个页面的最大滚动范围
    // _calcMaxScrollExtent(index);
  }

  // 重置页面容器高度
  void _resetPageViewHeight() {
    final height = _cachedHorizontalContentHeights[_currentPage] ?? 10000;
    _pageViewHeight.value = height;
  }

  /// 重置页面的偏移量
  void _resetPageOffset() {
    bool shouldResetScrollOffset = false;
    for (var i = 0; i < widget.horizontalContents.length; i++) {
      final valueNotifier = _contentOffsets[i]!;
      if (i == _currentPage && valueNotifier.value != 0) {
        shouldResetScrollOffset = true;
      }
      valueNotifier.value = 0;
    }

    if (shouldResetScrollOffset && _verticalScrollController.offset > _pinnedHeaderOffset) {
      _verticalScrollController.jumpTo(_pinnedHeaderOffset);
    }
  }

  // 设置其它页面的偏移量
  // 依赖 [_pinnedHeaderOffset]
  void _setOtherPageOffset() {
    if (_verticalScrollController.positions.isEmpty) {
      return;
    }

    // final page = _horizontalPageController.page ?? 0;
    final page = widget.tabController.index;
    if (page != page.toInt()) {
      return;
    }

    for (var i = 0; i < widget.horizontalContents.length; i++) {
      final valueNotifier = _contentOffsets[i]!;
      if (i == page) {
        if (valueNotifier.value != 0) {
          valueNotifier.value = 0;
        }
        continue;
      }
      final offset = _verticalScrollController.offset;
      if (offset < _pinnedHeaderOffset) {
        valueNotifier.value = 0;
      } else {
        valueNotifier.value = offset - _pinnedHeaderOffset;
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    SchedulerBinding.instance.addPostFrameCallback((timeStamp) {
      _calcPinnedHeaderOffset();
    });
    return GTRefreshCustomView(
      onRefresh: widget.onRefresh,
      enablePullUp: widget.enablePullUp ?? false,
      onLoading: widget.onLoad,
      child: _buildScrollView(),
      initRefresh: widget.initRefresh,
    );
  }

  Widget _buildScrollView() {
    return CustomScrollView(
      key: _customScrollViewKey,
      controller: _verticalScrollController,
      slivers: [
        ...widget.slivers,
        SliverPersistentHeader(
          delegate: GTLinkedCustomSliverPersistentHeaderDelegate(
            key: _pinnedHeaderKey,
            maxHeight: widget.pinnedWidgetHeight,
            minHeight: widget.pinnedWidgetHeight,
            child: widget.pinnedWidget,
          ),
          pinned: true,
        ),
        ValueListenableBuilder(
          valueListenable: _minPageHeight,
          child: _buildPages(),
          builder: (context, minPageHeight, child) => ValueListenableBuilder(
            valueListenable: _pageViewHeight,
            child: child,
            builder: (context, value, child) {
              final itemExtent = max(minPageHeight, value);
              return SliverFixedExtentList.list(
                itemExtent: itemExtent,
                children: [child!],
              );
            },
          ),
        ),
      ],
    );
  }

  Widget _buildPages() {
    final children = <Widget>[];
    for (var i = 0; i < widget.horizontalContents.length; i++) {
      children.add(
        SingleChildScrollView(
          physics: const NeverScrollableScrollPhysics(),
          child: ValueListenableBuilder(
            valueListenable: _contentOffsets[i]!,
            child: GTLinkedAfterLayout(
              callback: (ral) {
                _setPageHeight(i, ral.size.height);
              },
              child: widget.horizontalContents[i],
            ),
            builder: (context, value, child) {
              return Transform.translate(
                offset: Offset(0, value),
                child: child,
              );
            },
          ),
        ),
      );
    }
    return ScrollConfiguration(
      behavior: GTLinkedNoEffectScrollBehavior(),
      child: Listener(
        onPointerDown: (event) {
          _isPointerUp = false;
        },
        onPointerUp: (event) {
          _isPointerUp = true;
        },
        // child: RawGestureDetector(
        //   gestures: {
        //     CustomHorizontalDragGestureRecognizer:
        //         GestureRecognizerFactoryWithHandlers<CustomHorizontalDragGestureRecognizer>(
        //       () => CustomHorizontalDragGestureRecognizer(),
        //       initializerGestureRecognizer,
        //     ),
        //   },
        //   child: PageView(
        //     controller: _horizontalPageController,
        //     allowImplicitScrolling: true,
        //     physics: const NeverScrollableScrollPhysics(),
        //     pageSnapping: false,
        //     children: children,
        //   ),
        // ),
        child: ExtendedTabBarView(
          controller: widget.tabController,
          link: true,
          cacheExtent: 3,
          children: children,
        ),
      ),
    );
  }

  void initializerGestureRecognizer(GTLinkedCustomHorizontalDragGestureRecognizer instance) {
    final width = MediaQuery.of(context).size.width;
    instance.getPage = () {
      // return _horizontalPageController.page ?? 0;
      final page = widget.tabController.index;
      return page.toDouble();
    };
    instance.getWidth = () {
      return width;
    };

    double tempOffset = 0;
    instance.customOnStart = (details) {
      // tempOffset = _horizontalPageController.offset;
      tempOffset = widget.tabController.offset;
    };
    instance.customOnUpdate = (details) {
      tempOffset += -details.delta.dx;
      tempOffset = min(max(tempOffset, 0), width);
      debugPrint('Finance - Update: $tempOffset');
      // _horizontalPageController.jumpTo(tempOffset);
    };
    instance.customOnEnd = (details) {
      final velocity = details.primaryVelocity ?? 0;
      final offset = tempOffset -= velocity * 0.25;
      final page = offset > width / 2 ? 1 : 0;
      debugPrint('Finance - End: $offset - $page');
      // _horizontalPageController.animateToPage(
      //   page.round(),
      //   duration: const Duration(milliseconds: 200),
      //   curve: Curves.easeOut,
      // );
    };
    instance.customOnCancel = () {
      // final offset = tempOffset;
      // final page = offset > width / 2 ? 1 : 0;
      // _horizontalPageController.animateToPage(
      //   page.round(),
      //   duration: const Duration(milliseconds: 200),
      //   curve: Curves.easeOut,
      // );
    };
  }
}

class GTLinkedNoEffectScrollBehavior extends ScrollBehavior {
  @override
  Widget buildOverscrollIndicator(BuildContext context, Widget child, ScrollableDetails details) {
    return child;
  }
}

typedef GTLinkedAfterLayoutCallback = Function(GTLinkedRenderAfterLayout ral);

class GTLinkedAfterLayout extends SingleChildRenderObjectWidget {
  const GTLinkedAfterLayout({
    Key? key,
    required this.callback,
    Widget? child,
  }) : super(key: key, child: child);

  @override
  RenderObject createRenderObject(BuildContext context) {
    return GTLinkedRenderAfterLayout(callback);
  }

  @override
  void updateRenderObject(context, GTLinkedRenderAfterLayout renderObject) {
    renderObject.callback = callback;
  }

  final GTLinkedAfterLayoutCallback callback;
}

class GTLinkedRenderAfterLayout extends RenderProxyBox {
  GTLinkedRenderAfterLayout(this.callback);

  ValueSetter<GTLinkedRenderAfterLayout> callback;

  @override
  void performLayout() {
    super.performLayout();
    SchedulerBinding.instance.addPostFrameCallback((timeStamp) => callback(this));
  }

  Offset get offset => localToGlobal(Offset.zero);

  Rect get rect => offset & size;
}

class GTLinkedCustomSliverPersistentHeaderDelegate extends SliverPersistentHeaderDelegate {
  final Key key;
  final double maxHeight;
  final double minHeight;
  final Widget child;

  GTLinkedCustomSliverPersistentHeaderDelegate({
    required this.key,
    required this.maxHeight,
    required this.minHeight,
    required this.child,
  });

  @override
  Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
    return Container(
      key: key,
      child: child,
    );
  }

  @override
  double get maxExtent => maxHeight;

  @override
  double get minExtent => minHeight;

  @override
  bool shouldRebuild(GTLinkedCustomSliverPersistentHeaderDelegate oldDelegate) {
    return maxHeight != oldDelegate.maxHeight || minHeight != oldDelegate.minHeight || child != oldDelegate.child;
  }
}

class GTLinkedCustomHorizontalDragGestureRecognizer extends HorizontalDragGestureRecognizer {
  double Function()? getPage;
  double Function()? getWidth;

  int? _initialPointer;
  bool _isStart = false;

  void Function(DragStartDetails)? customOnStart;
  void Function(DragUpdateDetails)? customOnUpdate;
  void Function(DragEndDetails)? customOnEnd;
  void Function()? customOnCancel;

  GTLinkedCustomHorizontalDragGestureRecognizer() {
    onStart = (details) {
      debugPrint('Finance - Start');
      _isStart = true;
      customOnStart?.call(details);
    };
    onUpdate = (details) {
      debugPrint('Finance - Update');
      customOnUpdate?.call(details);
    };
    onEnd = (details) {
      debugPrint('Finance - End');
      _initialPointer = null;
      _isStart = false;
      customOnEnd?.call(details);
    };
    onCancel = () {
      debugPrint('Finance - Cancel');
      _initialPointer = null;
      if (_isStart) {
        customOnCancel?.call();
      }
      _isStart = false;
    };
  }

  @override
  void handleEvent(PointerEvent event) {
    debugPrint('Finance - ${event.runtimeType} - ${event.pointer} - $_initialPointer - $_isStart');

    if (!_isStart && event is PointerMoveEvent) {
      final page = getPage?.call() ?? 0;
      if (page == 1) {
        final dx = event.delta.dx;
        final localPosition = event.localPosition;
        final width = getWidth?.call() ?? 0;

        if (dx != 0) {
          if (dx < 0) {
            rejectGesture(event.pointer);
            debugPrint('Finance - Reject');
            return;
          } else if (localPosition.dx > width * 0.7) {
            rejectGesture(event.pointer);
            debugPrint('Finance - Reject');
            return;
          }
        }
      }
    }

    super.handleEvent(event);

    if (_isStart) {
      _initialPointer = event.pointer;
      debugPrint('Finance - InitialPointer: $_initialPointer');
    }
  }
}

class GTLinkedCustomExtendedTabBarView extends ExtendedTabBarView {
  const GTLinkedCustomExtendedTabBarView({
    super.key,
    required super.children,
    super.controller,
    super.physics,
    super.dragStartBehavior = DragStartBehavior.start,
    super.cacheExtent = 0,
    super.link = true,
    super.scrollDirection = Axis.horizontal,
    super.pageController,
    super.shouldIgnorePointerWhenScrolling = true,
    super.viewportFraction = 1.0,
  });

  @override
  ExtendedTabBarViewState createState() => GTLinkedCustomExtendedTabBarViewState();
}

class GTLinkedCustomExtendedTabBarViewState extends ExtendedTabBarViewState {
  @override
  Widget build(BuildContext context) {
    return super.build(context);
  }
}

class GTLinkedCustomScrollBehavior extends ScrollBehavior {
  const GTLinkedCustomScrollBehavior();

  @override
  Widget buildOverscrollIndicator(BuildContext context, Widget child, ScrollableDetails details) {
    switch (getPlatform(context)) {
      case TargetPlatform.android:
        return StretchingOverscrollIndicator(
          axisDirection: details.direction,
          child: child,
        );
      default:
        return super.buildOverscrollIndicator(context, child, details);
    }
  }
}
